package com.dw.provider;

import com.dw.common.bean.NetNode;
import com.dw.common.bean.ResourceBean;
import com.dw.common.configuration.Configuration;
import com.dw.common.service.KVService;
import com.dw.common.service.impl.KVServiceImpl;
import com.dw.common.util.ResourceScanner;
import com.dw.provider.api.ProviderImpl;
import io.grpc.Server;
import io.grpc.netty.NettyServerBuilder;
import lombok.Setter;

import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Map;
import java.util.concurrent.TimeUnit;

public class Provider {
    private static Map<ResourceBean, String> RESOURCES;
    private final KVService kvService;
    @Setter
    private String rootPath;
    private NetNode netNode;
    private Server rpcServer;

    public Provider() {
        kvService = new KVServiceImpl();
    }

    public static String getResourcePath(ResourceBean resource) {
        return RESOURCES.get(resource);
    }

    public void start() {
        setNetNode();
        register();
        try {
            startServer();
        } catch (IOException | InterruptedException e) {
            e.printStackTrace();
        }
    }

    private void register() {
        RESOURCES = ResourceScanner.scanOnlyFiles(rootPath);
        for (ResourceBean resource : RESOURCES.keySet()) {
            kvService.putWithLease(resource + ":" + Configuration.UUID,
                    Configuration.UUID);
        }
        kvService.putWithLease(Configuration.UUID, netNode);
    }

    private void startServer() throws IOException, InterruptedException {
        NettyServerBuilder builder = NettyServerBuilder.forPort(netNode.getPort());
        builder.addService(new ProviderImpl(netNode));
        builder.maxInboundMessageSize(Configuration.BATCH_SIZE);
        rpcServer = builder.build();
        rpcServer.start();
        blockUntilShutdown();
        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
            System.err.println("provider shutting down gRPC server since JVM is shutting down");
            try {
                Provider.this.stop();
            } catch (InterruptedException e) {
                e.printStackTrace(System.err);
            }
            System.err.println("provider server shut down");
        }));
    }

    private void setNetNode() {
        try {
            netNode = new NetNode();
            netNode.setIp(InetAddress.getLocalHost().getHostAddress());
            netNode.setPort(Configuration.PORT);
            netNode.setTaskCounts(0);
        } catch (UnknownHostException e) {
            e.printStackTrace();
        }
    }

    private void stop() throws InterruptedException {
        if (rpcServer != null) {
            rpcServer.shutdown().awaitTermination(30, TimeUnit.SECONDS);
        }
    }

    private void blockUntilShutdown() throws InterruptedException {
        if (rpcServer != null) {
            rpcServer.awaitTermination();
        }
    }
}
